use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::Mutex;
use tokio::time::sleep;
use reqwest::Client;
use reqwest::header::{RANGE, ACCEPT};
use tokio::io::AsyncWriteExt;
use futures_util::StreamExt;
use crate::utils::file_utils;
use thiserror::Error;

#[derive(Debug, Clone, serde::Serialize)]
pub struct DownloadProgress {
    pub percentage: f32,
    pub downloaded_bytes: u64,
    pub total_bytes: u64,
    pub speed: f64, // MB/s
    pub status: String,
    pub eta_seconds: u64,
}

impl Default for DownloadProgress {
    fn default() -> Self {
        Self {
            percentage: 0.0,
            downloaded_bytes: 0,
            total_bytes: 0,
            speed: 0.0,
            status: "准备中".to_string(),
            eta_seconds: 0,
        }
    }
}

#[derive(Error, Debug)]
pub enum PbfDownloadError {
    #[error("HTTP请求错误: {0}")]
    HttpError(#[from] reqwest::Error),
    
    #[error("IO错误: {0}")]
    IoError(#[from] std::io::Error),
    
    #[error("文件操作错误: {0}")]
    FileError(#[from] crate::utils::file_utils::FileUtilsError),
    
    #[error("下载被取消")]
    Cancelled,
    
    #[error("无效的响应")]
    InvalidResponse,
}

pub struct PbfDownloadService {
    source_url: String,
    output_path: String,
    max_speed: u64, // KB/s
    progress: Arc<Mutex<DownloadProgress>>,
}

impl PbfDownloadService {
    pub fn new(
        source_url: String,
        output_path: String,
        max_speed: u64,
        progress: Arc<Mutex<DownloadProgress>>,
    ) -> Self {
        Self {
            source_url,
            output_path,
            max_speed,
            progress,
        }
    }
    
    pub async fn download(&self) -> Result<(), PbfDownloadError> {
        let client = Client::new();
        
        // 首先获取文件大小
        let head_response = client.head(&self.source_url)
            .send()
            .await?;
            
        let total_bytes = head_response.headers()
            .get("content-length")
            .and_then(|val| val.to_str().ok())
            .and_then(|s| s.parse().ok())
            .ok_or(PbfDownloadError::InvalidResponse)?;
        
        // 检查是否已部分下载
        let mut downloaded_bytes = 0;
        if tokio::fs::metadata(&self.output_path).await.is_ok() {
            downloaded_bytes = file_utils::get_file_size(&self.output_path).await?;
        }
        
        // 更新初始进度
        {
            let mut progress = self.progress.lock().await;
            progress.total_bytes = total_bytes;
            progress.downloaded_bytes = downloaded_bytes;
            progress.percentage = if total_bytes > 0 {
                (downloaded_bytes as f32 / total_bytes as f32) * 100.0
            } else {
                0.0
            };
            progress.status = "开始下载".to_string();
        }
        
        // 如果已经下载完成，直接返回
        if downloaded_bytes >= total_bytes {
            let mut progress = self.progress.lock().await;
            progress.percentage = 100.0;
            progress.status = "下载完成".to_string();
            return Ok(());
        }
        
        // 准备追加写入文件
        let mut file = tokio::fs::OpenOptions::new()
            .create(true)
            .append(true)
            .open(&self.output_path)
            .await?;
        
        // 发起范围请求
        let range_header = format!("bytes={}-", downloaded_bytes);
        let response = client.get(&self.source_url)
            .header(RANGE, range_header)
            .header(ACCEPT, "application/octet-stream")
            .send()
            .await?;
            
        if !response.status().is_success() {
            return Err(PbfDownloadError::InvalidResponse);
        }
        
        // 处理响应流
        let mut stream = response.bytes_stream();
        let mut last_progress_update = Instant::now();
        let mut bytes_since_last_update = 0;
        let max_chunk_size = self.max_speed * 1024; // 转换为字节
        let speed_check_interval = Duration::from_secs(1);
        
        while let Some(chunk) = stream.next().await {
            let chunk = chunk.map_err(PbfDownloadError::HttpError)?;
            let chunk_size = chunk.len() as u64;
            
            // 写入文件
            file.write_all(&chunk).await?;
            
            // 更新下载字节数
            downloaded_bytes += chunk_size;
            bytes_since_last_update += chunk_size;
            
            // 控制下载速度
            if chunk_size > max_chunk_size {
                let sleep_time = Duration::from_millis(
                    (chunk_size as f64 / max_chunk_size as f64 * 1000.0) as u64
                );
                sleep(sleep_time).await;
            }
            
            // 定期更新进度
            if last_progress_update.elapsed() >= speed_check_interval || downloaded_bytes >= total_bytes {
                let elapsed = last_progress_update.elapsed().as_secs_f64();
                let speed = bytes_since_last_update as f64 / elapsed / 1024.0 / 1024.0; // MB/s
                
                let remaining_bytes = total_bytes - downloaded_bytes;
                let eta_seconds = if speed > 0.0 {
                    (remaining_bytes as f64 / (speed * 1024.0 * 1024.0)) as u64
                } else {
                    0
                };
                
                let percentage = (downloaded_bytes as f32 / total_bytes as f32) * 100.0;
                let status = if percentage < 100.0 {
                    format!("下载中 ({:.1}%)", percentage)
                } else {
                    "下载完成".to_string()
                };
                
                // 更新进度
                let mut progress = self.progress.lock().await;
                progress.downloaded_bytes = downloaded_bytes;
                progress.percentage = percentage;
                progress.speed = speed;
                progress.eta_seconds = eta_seconds;
                progress.status = status;
                println!("更新进度...{}", percentage);
                // 重置计数器
                last_progress_update = Instant::now();
                bytes_since_last_update = 0;
            }
            
            // 检查是否下载完成
            if downloaded_bytes >= total_bytes {
                break;
            }
        }
        
        // 最终更新
        let mut progress = self.progress.lock().await;
        progress.percentage = 100.0;
        progress.status = "下载完成".to_string();
        progress.eta_seconds = 0;
        
        Ok(())
    }
}
